package cn.kgc.vue.service.impl;

import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.kgc.vue.commons.QueryCondition;
import cn.kgc.vue.entity.Permission;
import cn.kgc.vue.entity.RolePermission;
import cn.kgc.vue.entity.User;
import cn.kgc.vue.entity.UserRole;
import cn.kgc.vue.form.UserForm;
import cn.kgc.vue.mapper.*;
import cn.kgc.vue.response.ResponseResult;
import cn.kgc.vue.service.UserService;
import cn.kgc.vue.utils.IpUtil;
import cn.kgc.vue.utils.JWTUtil;
import cn.kgc.vue.vo.UserVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author mengshun
 * @description 针对表【sys_user】的数据库操作Service实现
 * @createDate 2024-09-20 13:48:02
 */
@Service
@Slf4j
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private JWTUtil jwtUtil;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private DeptMapper deptMapper;

    @Resource
    private UserRoleMapper userRoleMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private RolePermissionMapper rolePermissionMapper;

    @Resource
    private PermissionMapper permissionMapper;

    @Override
    public ResponseResult createCaptcha() {

        // 创建验证码对象
        LineCaptcha lineCaptcha = new LineCaptcha(110, 50, 4, 3);
        String code = lineCaptcha.getCode();
        //  存储验证码  redis   设置时效性  3min  uuid 作为redis的key   响应到前端 用户后续用户的认证的验证码标识
        String uuid = IdUtil.simpleUUID();
        stringRedisTemplate.opsForValue().set(uuid, code, 3, TimeUnit.MINUTES);

        // 将验证码图片转换成base64字符串   在前端可以通过拼接特定的前缀 直接将base64字符串转换成图片
        String imageBase64 = lineCaptcha.getImageBase64();

        return ResponseResult.success()
                .data("uuid", uuid)
                .data("imageBase64", imageBase64);
    }

    @Override
    public ResponseResult login(HashMap<String, Object> params, HttpServletRequest request) {

        // 1. 判定验证码  redis   uuid
        String uuid = (String) params.get("uuid");
        // 根据uuid获取redis中的验证码
        String redisCode = stringRedisTemplate.opsForValue().get(uuid);
        if (StringUtils.isBlank(redisCode)) {
            return ResponseResult.fail().message("验证码失效,请刷新重新获取");
        }
        // form表单中的验证码
        String formCode = (String) params.get("code");
        if (!StringUtils.equals(redisCode, formCode)) {
            return ResponseResult.fail().message("验证码错误...");
        }

        // 验证码验证通过   删除验证码
        stringRedisTemplate.delete(uuid);

        // 2. 判定用户名 和 密码
        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.eq(User::getUsername, params.get("username"));
        User user = baseMapper.selectOne(lambda);

        if (ObjectUtils.isNull(user)) {
            return ResponseResult.fail().message("用户名错误...");
        }

        //  判定用户状态
        Integer state = user.getState();
        if (state == 0) {  //  用户被禁用
            return ResponseResult.fail().message("用户被禁用,请联系管理员...");
        }

        // 比较密码   formPassword  明文  DBPassword
        String formPassword = (String) params.get("password");
        String salt = user.getSalt();
        formPassword = new SimpleHash("MD5", formPassword, salt, 10).toHex();
        String DBPassword = user.getPassword();

        if (!StringUtils.equals(formPassword, DBPassword)) {
            return ResponseResult.fail().message("密码错误...");
        }

        // 3. 创建token   响应给前端
        HashMap<String, Object> claims = new HashMap<>();
        claims.put("username", user.getUsername());
        claims.put("uid", user.getId());

        String token = jwtUtil.createToken(claims);
        log.info("token={}", token);

        // 将token和ip绑定 避免token的盗用
        String ip = IpUtil.getIp(request);
        stringRedisTemplate.opsForValue().set(token, ip);

        return ResponseResult.success()
                .message("认证通过")
                .data("token", token)
                .data("nickName", user.getNickName());
    }

    @Override
    public ResponseResult logout(HttpServletRequest request) {
        String token = request.getHeader("authorization");
        stringRedisTemplate.delete(token);
        return ResponseResult.success().message("安全退出");
    }

    @Override
    public ResponseResult userPage(QueryCondition<User> queryCondition) {

        Integer page = queryCondition.getPage();
        Integer limit = queryCondition.getLimit();
        User searchParams = queryCondition.getSearchParams();
        String username = searchParams.getUsername();
        Integer deptId = searchParams.getDeptId();
        Integer state = searchParams.getState();


        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.like(StringUtils.isNotBlank(username), User::getUsername, username)
                .eq(ObjectUtils.isNotNull(deptId), User::getDeptId, deptId)
                .eq(ObjectUtils.isNotNull(state), User::getState, state)
                .orderByDesc(User::getCreateTime);

        Page<User> userPage = new Page<User>(page, limit);
        baseMapper.selectPage(userPage, lambda);

        long total = userPage.getTotal();
        List<User> records = userPage.getRecords();

        List<UserVO> collect = records.stream().map(user -> {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);

            // 查询用户部门信息
            String deptName = deptMapper.selectById(user.getDeptId()).getDeptName();
            userVO.setDeptName(deptName);

            // 查询用户角色列表
            Integer id = user.getId();
            HashMap<String, Object> params = new HashMap<>();
            params.put("user_id", id);
            List<Integer> rids = userRoleMapper.selectByMap(params).stream()
                    .map(ur -> ur.getRoleId()).collect(Collectors.toList());

            // 设置角色id  用于用户数据回显
            userVO.setRoleId(rids);

            List<String> roleNames = roleMapper.selectBatchIds(rids).stream()
                    .map(role -> role.getRoleCh())
                    .collect(Collectors.toList());

            userVO.setRoleNames(roleNames);
            return userVO;
        }).collect(Collectors.toList());

        return ResponseResult.success()
                .data("total", total)
                .data("tableData", collect);
    }

    /*
     * userForm    user  user_role
     * */
    @Override
    public ResponseResult addUser(UserForm userForm) {

        // 添加数据到用户表
        User user = new User();
        BeanUtils.copyProperties(userForm,user);

        // 设置用户的默认密码
        String defaultPwd = "123456";
        String salt = RandomUtil.randomString(8);

        String hex = new SimpleHash("MD5", defaultPwd, salt, 10).toHex();
        user.setPassword(hex);
        user.setSalt(salt);
        // 数据库中用户名字段有唯一索引  不需要在通过查询判定用户名是否存在   如果重复会直接抛出异常信息
        baseMapper.insert(user);

        // 添加用户角色到  user_role
        List<Integer> roleId = userForm.getRoleId();
        Integer uid = user.getId();

        roleId.stream().forEach(rid->{
            UserRole userRole = new UserRole(uid, rid);
            userRoleMapper.insert(userRole);
        });

        return ResponseResult.success().message("添加成功");
    }

    @Override
    public ResponseResult editUser(UserForm userForm) {

        //  1. 更新数用户表
        User user = new User();
        BeanUtils.copyProperties(userForm,user);

        // 乐观锁   version
        int line = baseMapper.updateById(user);

        if (line==1){
            // 2. 根据用户id  删除用户角色信息  user_role
            Integer uid = user.getId();
            LambdaQueryWrapper<UserRole> lambda = new QueryWrapper<UserRole>().lambda();
            lambda.eq(UserRole::getUserId,uid);
            userRoleMapper.delete(lambda);

            // 3. 添加最新的角色信息
            List<Integer> roleId = userForm.getRoleId();
            roleId.stream().forEach(rid->{
                UserRole userRole = new UserRole(uid, rid);
                userRoleMapper.insert(userRole);
            });

            return  ResponseResult.success().message("数据编辑成功");
        }else {
            return ResponseResult.fail().message("更新失败,请刷新重试...");
        }

    }

    @Override
    public ResponseResult batchDelete(List<Integer> ids) {

        // 1. 删除用户表中的数据   user
        baseMapper.deleteByIds(ids);

        //  2. 删除用户角色关联表中的数据  user_role
        LambdaQueryWrapper<UserRole> lambda = new QueryWrapper<UserRole>().lambda();
        lambda.in(UserRole::getUserId,ids);
        userRoleMapper.delete(lambda);

        return ResponseResult.success();
    }

    @Override
    public ResponseResult getPersonalInfo(HttpServletRequest request) {

        String authorization = request.getHeader("authorization");
        Map<String, Object> claims = jwtUtil.getClaims(authorization);
        Integer uid = (Integer) claims.get("uid");
        User user = baseMapper.selectById(uid);

        return ResponseResult.success().data("personalInfo",user);
    }

    @Override
    public ResponseResult editPersonalInfo(UserForm userForm) {

        //  判定验证码是否正确
        String formCode= userForm.getCode();
        String redisEmailCode = stringRedisTemplate.opsForValue().get(userForm.getEmail());

        if (StringUtils.isBlank(redisEmailCode)){
            return  ResponseResult.fail().message("验证码已失效,请重新获取...");
        }

        if (!StringUtils.equals(redisEmailCode,formCode)){
            return ResponseResult.fail().message("验证码错误...");
        }

        User user = new User();
        BeanUtils.copyProperties(userForm,user);

        baseMapper.updateById(user);

        return ResponseResult.success().message("个人信息编辑成功");
    }

    @Override
    public ResponseResult editPersonalPassword(Map<String, String> params, HttpServletRequest request) {

        // 获取用户输入的新旧密码
        String oldPassword = params.get("oldPassword");
        String newPassword = params.get("newPassword");


        // 获取token 解析用户信息
        String authorization = request.getHeader("authorization");
        Integer uid = (Integer) jwtUtil.getClaims(authorization).get("uid");

        User user = baseMapper.selectById(uid);
        String DBPassword = user.getPassword();
        String salt = user.getSalt();

        String formPassword = new SimpleHash("MD5", oldPassword, salt, 10).toHex();
        if (!StringUtils.equals(DBPassword,formPassword)){
            return ResponseResult.fail().message("原始密码不正确");
        }

        // 将新密码加密处理
        String newPwd = new SimpleHash("MD5",newPassword,salt,10).toHex();

        LambdaUpdateWrapper<User> lambda = new UpdateWrapper<User>().lambda();
        lambda.set(User::getPassword,newPwd)
                .eq(User::getId,uid);

        baseMapper.update(lambda);

        return ResponseResult.success().message("密码修改成功");
    }


    @Override
    public ResponseResult menuList(HttpServletRequest request) {
        String authorization = request.getHeader("authorization");
        Integer uid = (Integer) jwtUtil.getClaims(authorization).get("uid");

        LambdaQueryWrapper<UserRole> lambda = new QueryWrapper<UserRole>().lambda();
        lambda.eq(UserRole::getUserId,uid);

        List<Integer> rids = userRoleMapper.selectList(lambda).stream()
                .map(ur -> ur.getRoleId())
                .collect(Collectors.toList());

        // 根据角色id  查询权限信息   按钮  菜单权限
        LambdaQueryWrapper<RolePermission> lambda1 = new QueryWrapper<RolePermission>().lambda();
        lambda1.in(RolePermission::getRoleId,rids);

        Set<Integer> pIds = rolePermissionMapper.selectList(lambda1).stream()
                .map(rp -> rp.getPerId())
                .collect(Collectors.toSet());

        LambdaQueryWrapper<Permission> lambda2 = new QueryWrapper<Permission>().lambda();
        lambda2.in(Permission::getId,pIds)
                .ne(Permission::getIsMenu,2);

        // 用户目录权限  菜单权限
        List<Permission> permissions = permissionMapper.selectList(lambda2);

        return ResponseResult.success().data("menuList",permissions);
    }
}




